home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Snippets / NewStringArt 1.0.2 / NewStringArt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-01  |  11.5 KB  |  377 lines  |  [TEXT/CWIE]

  1. // NewStringArt
  2. // version 1.0.2
  3. // adapted from a Sun Microsystems demo by Ron Hitchens
  4. // ported to CodeWarrior by Ken Long <kenlong@netcom.com>
  5. // updated for CW7 on 951201
  6.  
  7. /*    This program is public domain.  It may be be freely distributed,
  8.  *    copied and used.  All I ask is that my name and this notice remain
  9.  *    on it.  And that modifications be noted in this source listing and
  10.  *    returned to me if possible at the above email address.
  11.  *
  12.  *    History:
  13.  *        May 85    Hitchens    Created.
  14.  *        May 28    Hitchens    Look at screen size vars, add comments
  15.  *
  16.  *
  17.  *    Compilation instructions with Megamax C:
  18.  *    You need the C source files stringart.c and gennums.c
  19.  *        1. compile and link gennums.c
  20.  *        2. run gennums, it creates a C source file named stringnums.c
  21.  *          This name is hard-coded in gennums.c
  22.  *        3. Compile stringnums.c, but don't link it.  Keep stringnums.o
  23.  *        4. Compile stringart.c
  24.  *        5. Link stringart.o and stringnums.o together to make stringart
  25.  *        6. Run StringArt.
  26.  *        7. Sit back and enjoy the show.
  27.  *    If you make changes to stringart, after doing the above, you can skip
  28.  *    to 4.  Stringnums doesn't need to be re-compiled.
  29.  *    If you want to port this to another flavor of C you're on your own.
  30.  *
  31.  *    The icon was created manually with the resource editor, to retain
  32.  *    the icon when recompiling just specify the name of the old 
  33.  *    StringArt application file as the output of the linker.  It will
  34.  *    overwrite the code but won't disturb the icon resources.
  35.  */
  36.  
  37. /*
  38.     This demo creates random vector designs.  This is accomplished by
  39.     randomly choosing a function for each coordinate halve of the two
  40.     points describing a vector that moves through two dimensional
  41.     space. Both x coordinate halves cannot be the same since the design
  42.     would simply be a collection of vertical lines. Similarly both
  43.     y coordinate halves cannot be the same.
  44.  
  45.     The functions are:
  46.  
  47.     function[0][x] = sin( 2 * PI * x / numLines )
  48.     function[1][x] = -sin( 2 * PI * x / numLines )
  49.     function[2][x] = cos( 2 * PI * x / numLines ) 
  50.     function[3][x] = -cos( 2 * PI * x / numLines ) 
  51.     function[4][x] = sin( 4 * PI * x / numLines )
  52.     function[5][x] = -sin( 4 * PI * x / numLines )
  53.     function[6][x] = cos( 4 * PI * x / numLines ) 
  54.     function[7][x] = -cos( 4 * PI * x / numLines ) 
  55.     function[8][x] = sin( 6 * PI * x / numLines )
  56.     function[9][x] = -sin( 6 * PI * x / numLines )
  57.     function[10][x] = cos( 6 * PI * x / numLines ) 
  58.     function[11][x] = -cos( 6 * PI * x / numLines ) 
  59.     function[12][x] = 2 * abs( x - (numLines / 2) - 1 )    *not used*
  60.  
  61.     The values of the functions were pre-computed to have the demo
  62.     run as fast as possible.  The program runs in an endless loop, it 
  63.     will terminate if the "Quit" menu item is selected or a 'Q' is typed.
  64. */
  65.  
  66. #define numLines    343    /* number of vectors in a design */
  67. #define num_functions    12    /* number of functions */
  68. #define Voffset        19    /* offset from top, drag is under menu bar */
  69. #define border        2    /* surrounding blank border */
  70.                 
  71. /* get real size of screen, in case of Lisa or something new */
  72. #define Hsize (qd.screenBits.bounds.right)
  73. #define Vsize (qd.screenBits.bounds.bottom)
  74.  
  75. WindowRecord    myRecord;    /* if you can't figure out what these are */
  76. WindowPtr    myWindow;    /* you'd better give up right now */
  77. MenuHandle    myMenu;
  78.  
  79. short holding = 0;        /* are we currently holding? */
  80. short step = 0;            /* single step? */
  81.  
  82. short q [4][numLines];        /* temp array for scaled coordinates */
  83. extern short p [num_functions][numLines];
  84.     /* pre-computed points, scaled by 1024 */
  85. long ticks;
  86.  
  87. main()
  88. {
  89.     short i, j, k, l, m;
  90.     long secs;
  91.     
  92.     Init ();        /* do housekeeping */
  93.     ShowInfo ();        /* display bragging info */
  94.     GetDateTime ((unsigned long*) qd.randSeed);    /* randomize the Random() function */
  95.  
  96.     while (1) {        /* main loop, go round and round forever */
  97.         /* pick the functions */
  98.         while ((i = Random() % num_functions) < 0) /* nothing */ ;
  99.         while ((j = Random() % num_functions) == i || (j < 0));
  100.         while ((k = Random() % num_functions) < 0);
  101.         while ((l = Random() % num_functions) == k || (l < 0));
  102.  
  103.         /* scalepoints was a hack to speed up the line drawing, by
  104.           avoiding the scaling computations for each coordinate
  105.           while the lines are being drawn.  It didn't help as much
  106.           as I'd hoped, only about a second is saved, maybe less.
  107.           Apparently I'm pushing QuickDraw as fast as it will go.
  108.           The same calculations using floating point took about
  109.           45 seconds, YOW! */
  110.             
  111.         ScalePoints (i, k, j, l);    /* scale to the window */
  112.         while (holding && !step)    /* loop here if holding */
  113.             CheckMenu ();        /* watch events when holding */
  114.  
  115.         BlankWindow (myWindow);        /* clear to black or white */
  116.         SetPort (myWindow);        /* point QD at my window */
  117.             /* the above statement shouldn't be necessary, but
  118.               something sneaky, like the screensaver DA, could
  119.               be lurking in the darkness and may change the
  120.               grafport out from under us.  Grrr... */
  121.         ObscureCursor ();        /* get rid of the cursor */
  122.  
  123.         for (m = 0; m < numLines; m++) {    /* draw the vectors */
  124.             MoveTo (q [0][m], q [1][m]);
  125.             LineTo (q [2][m], q [3][m]);
  126.         }
  127.  
  128.         SystemTask ();            /* in case of DAs */
  129.         if (! holding) 
  130.             Delay (60L, &ticks);    /* pause for ~6 secs */
  131.         step = 0;            /* only good for one shot */
  132.     }
  133. }
  134.  
  135.  
  136. /* the numbers in the array p were pre-computed using floating point
  137.    arithmetic, they were all sin or cos functions and so yielded
  138.    numbers [-1, 1].  These numbers were then scaled up by 1024 so they
  139.    could be stored as integers.  1024 was used so they could be scaled down
  140.    again with a shift-right-10 rather than a divide operation.  I use two
  141.    statements to compute each number to be sure the intermediate values
  142.    are calculated as longs, the values involved far exceed the magnitude
  143.    possible in a 16-bit short.  */
  144.      
  145. ScalePoints (x1, y1, x2, y2)    short x1, y1, x2, y2;
  146. {
  147.     long  l, h, v;
  148.     short i;
  149.     
  150.     h = (Hsize) / 2;
  151.     v = (Vsize - Voffset) / 2;
  152.     for (i = 0; i < numLines; i++) {
  153.         l = (((long)p [x1][i] * (h - border)) >> 10) + h;
  154.         q [0][i] = (short)l;
  155.         l = (((long)p [y1][i] * (v - border)) >> 10) + v;
  156.         q [1][i] = (short)l;
  157.         l = (((long)p [x2][i] * (h - border)) >> 10) + h;
  158.         q [2][i] = (short)l;
  159.         l = (((long)p [y2][i] * (v - border)) >> 10) + v;
  160.         q [3][i] = (short)l;
  161.         CheckMenu ();    /* see if there are any events to be handled */
  162.     }
  163. }
  164.  
  165.  
  166. CheckMenu ()
  167.     /* test for and handle any events, such as keyboard and mouse */
  168. {
  169.     EventRecord    theEvent;
  170.     WindowPtr    tmpPtr;
  171.  
  172.             /* loop as long as there are events in the queue */
  173.     while (GetNextEvent (everyEvent, &theEvent)) {
  174.         switch (theEvent.what) 
  175.         {
  176. //            case abortEvt:        /* something is telling us to stop */
  177. //                exit (0);
  178.             case keyDown:        /* got a key */
  179.                     /* does this key belong to a menu? */
  180.                 if (MenuKey ((char) (theEvent.message % 256))) 
  181.                 {    /* yes */
  182.                     Do_Menu (MenuKey ((char) (theEvent.message % 256)));
  183.                 } 
  184.                 else 
  185.                     {
  186.                         step = 1;    /* step once (undoc feature) */    
  187.                         return;
  188.                 }
  189.             break;
  190.             
  191.             case mouseDown:        /* mouse clicked */
  192.                 if (FindWindow(theEvent.where, &tmpPtr) == inMenuBar)
  193.                 {
  194.                     Do_Menu (MenuSelect (theEvent.where));
  195.                 } else {
  196.                     step = 1;    /* cycle once */
  197.                 }
  198.             break;
  199.     
  200.             case updateEvt:    /* always get one of these at startup */
  201.                 BeginUpdate (myWindow);
  202.                 EndUpdate (myWindow);    /* only way to get rid of it */
  203.             break;
  204.         
  205.             case nullEvent:    /* shouldn't happen, filtered above */
  206.                 return;
  207.         
  208.             default:
  209.             break;        /* not interested in anything else */
  210.         }
  211.     }
  212. }
  213.  
  214. Do_Menu (item)        long item;    /* handle a menu selection */
  215. {
  216.     HiliteMenu (1);
  217.     switch (item) 
  218.     {
  219.         case 0x00010001:        /* menu 1, item 1 (hold) */
  220.             Toggle_Hold ();
  221.         break;
  222.         
  223.         case 0x00010002:        /* menu 1, item 2 (invert) */
  224.             Invert ();
  225.         break;
  226.         
  227.         case 0x00010003:        /* menu 1, item 3 (author info) */
  228.             ShowInfo ();
  229.         break;
  230.         
  231.         case 0x00010004:        /* menu1, item 4 (quit) */
  232.             ExitToShell ();
  233.     }
  234.     HiliteMenu (0);
  235. }
  236.     
  237.  
  238. Toggle_Hold ()
  239. {
  240.     holding = !holding;        /* toggle the flag */
  241.     CheckItem (myMenu, 1,  holding);
  242.         /* place or remove checkmark, depending on holding */
  243. }
  244.  
  245. Invert ()
  246. {
  247.     SetPort (myWindow);            /* on the off chance... */
  248.     if (myWindow->pnMode == patBic) {
  249.         PenMode (patCopy);            /* draw black */
  250.         TextMode (srcCopy);
  251.     } 
  252.     else 
  253.         {
  254.             PenMode (patBic);            /* draw white */
  255.             TextMode (srcBic);
  256.     }
  257.     InvertRect (&myWindow->portRect);    /* flip what's onscreen */
  258. }
  259.             
  260.  
  261. Init ()                    /* do initial housekeeping chores */
  262. {
  263.     ManagerInits ();
  264.     WindowInits ();
  265.     MenuInits ();
  266. }
  267.  
  268. ManagerInits()
  269. {
  270.        InitGraf(&qd.thePort);        /* initialize qd (theport in qd) */
  271.     InitFonts();            /* initialize font manager */
  272.     InitWindows();            /* initialize window manager */
  273.     InitMenus();            /* initialize menus */
  274.     InitCursor();            /* set cursor to arrow */
  275.     FlushEvents(everyEvent, 0);    /* lose any outstanding events */
  276. }
  277.  
  278. WindowInits()
  279. {
  280.     Rect        tempRect;
  281.     
  282.     SetRect(&tempRect, 0, Voffset, Hsize, Vsize);
  283.     myWindow = NewWindow(&myRecord, &tempRect, "\pStringart", 1, 0,
  284.                 (WindowPtr)-1L, 0, (long) 0);
  285.     SetPort(myWindow);        /* draw in my window */
  286.     SelectWindow(myWindow);        /* make mine active */
  287.     PenNormal ();            /* make sure pen has defaults */
  288.     PenMode (patBic);        /* make it draw white */
  289.     TextMode (srcBic);        /* make text draw white */
  290.     TextFont (0);            /* use system font */
  291.     TextFace ((short) bold);    /* use a fancy text style */
  292. }
  293.  
  294. MenuInits ()
  295. {
  296.     myMenu = NewMenu (1, "\pStringArt");    /* allocate a menu struct */
  297.     AppendMenu (myMenu,  "\pHold/H");        /* load the item values */
  298.     AppendMenu (myMenu, "\pInvert/I");
  299.     AppendMenu (myMenu, "\pAuthor Info/A");
  300.     AppendMenu (myMenu, "\pQuit/Q");
  301.     InsertMenu (myMenu, 0);            /* let the OS know about it */
  302.     DrawMenuBar ();                /* make it show up */
  303. }
  304. /*
  305. Sleep (short s)
  306.     // sleep for approx s seconds, could vary from s-1 to s seconds
  307. {
  308.     unsigned long s1, s2;
  309.  
  310.     GetDateTime ((unsigned long*) s1);        //what time is it now?
  311.     s1 += s;            // looking for now + s seconds.
  312.     while (1) 
  313.     {
  314.         GetDateTime ((unsigned long*) s2);
  315.         if (s1 <= s2) 
  316.             break;    // ok, the time has come.
  317.         CheckMenu ();        // keep an eye on events around you.
  318.     }
  319. }
  320. */
  321. BlankWindow (w)        WindowPtr w;
  322. {
  323.     if (w->pnMode == patBic) 
  324.     {    /* drawing white? */
  325.         FillRect (&w->portRect, &qd.black); /* yes, paint window black */
  326.     } 
  327.     else 
  328.         {
  329.             FillRect (&w->portRect, &qd.white); /* no, paint it white */
  330.     }
  331. }
  332.  
  333. short width;
  334.  
  335. ShowInfo ()        /* display bragging info */
  336. {
  337.     static char *s [] = {
  338.         (char*) "\pStringArt by Ron Hitchens.",
  339.         (char*) "\p13 September 1985.",
  340.         (char*) "\phitchens@ut-sally.ARPA  or  ...!ihnp4!ut-sally!hitchens.UUCP",
  341.         (char*) "\p", 
  342.         (char*) "\pWritten in MegaMax C.",
  343.         (char*) "\pThis program is public domain.", 
  344.         (char*) "\p",
  345.         (char*) "\pWhile in Hold, click mouse to single step",
  346.         (char*) "\pTo save an image, type:  SHIFT/CMD/3. (duh)" ,
  347.         (char*) "\pTo print an image, type:  SHIFT/CMD/4. (duh)",
  348.         (char*) "\p", 
  349.         (char*) "\pMade to run in Code Warrior as",
  350.         (char*) "\pan itty bitty bytes™ revival project, ",
  351.         (char*) "\pperpetrated by Kenneth A. Long - 20 Nov 94." 
  352.     };
  353.     
  354.     short i, n;
  355.     static int busy = 0;
  356.     
  357.     HiliteMenu (1);            /* turn on the menu */
  358.     if (busy) return;        /* info screen already up */
  359.     busy = 1;            /* to prevent recursive displays */
  360.     SetPort (myWindow);        /* just in case */
  361.     ObscureCursor ();        /* get rid of the cursor */
  362.     BlankWindow (myWindow);
  363.     n = sizeof (s) / sizeof (s [0]);    /* how many lines of text? */
  364.     TextSize (24);                /* get fancy for first line */
  365.     for (i = 0; i < n; i++) {        /* display all the text */
  366.         MoveTo ((Hsize / 2) - (StringWidth ((StringPtr) s [i]) / 2),
  367.             (Vsize / (n + 1)) + (i * (Vsize / (n + 1))));
  368.         DrawString ((StringPtr) s [i]);    /* draw one of the text lines */
  369.         TextSize (12);        /* back to normal for the rest */
  370.     }
  371.     if (!holding) 
  372.         Delay (60L, &ticks);        /* wait a bit */
  373.     HiliteMenu (0);                /* turn off the menu */
  374.     busy = 0;                /* ok, I'm finished */
  375. }
  376.  
  377.